/**
 * 语义分析功能
 *
 * 当前特性：
 * 1.简单的符号表
 * 2.简单的函数消解
 * 3.简单的变量消解
 *
 */

package mynl

import (
	"fmt"
	"strings"
)

/////////////////////////////////////////////////////////////////////////
// 符号表
//

/**
 * 符号表
 * 保存变量、函数、类等的名称和它的类型、声明的位置（AST节点）
 */
type SymTable struct {
	Table map[string]Symbol
}

func NewSymTable() *SymTable {
	var Table = make(map[string]Symbol)
	return &SymTable{Table: Table}
}

func (selfx *SymTable) enterSymbol(Name string, decl interface{}, symType SymKind) {
	selfx.Table[Name] = *NewSymbol(Name, decl, symType)
}

func (selfx *SymTable) hasSymbol(Name string) bool {
	var _, ok = selfx.Table[Name]
	return ok
}

/**
 * 根据名称查找符号。
 * @param Name 符号名称。
 * @returns 根据名称查到的Symbol。如果没有查到，则返回null。
 */
func (selfx *SymTable) getSymbol(Name string) *Symbol {
	var item, ok = selfx.Table[Name]
	if ok {
		return &item
	} else {
		return nil
	}
}

/**
 * 符号表条目
 */
type Symbol struct {
	Name  string
	Value interface{}
	Kind  SymKind
}

func NewSymbol(Name string, value interface{}, kind SymKind) *Symbol {
	return &Symbol{
		Name:  Name,
		Value: value,
		Kind:  kind,
	}
}

/**
 * 符号类型
 */
type SymKind int

const (
	SymKind_Variable SymKind = iota
	SymKind_Function
	SymKind_Class
	SymKind_Interface
)

func (selfx *SymKind) String() string {
	var x = []string{"Variable", "Function", "Class", "Interface"}
	return x[*selfx]
}

/////////////////////////////////////////////////////////////////////////
// 建立符号表
//

/**
 * 把符号加入符号表。
 */
type Enter struct {
	AstVisitor
	symTable SymTable
}

func NewEnter(symTable SymTable) *Enter {
	return &Enter{
		symTable: symTable,
	}
}

func (selfx Enter) Visit(caller *IAstVisitor, node *IAstNode) interface{} {
	return (*node).Accept(caller)
}

/**
 * 把函数声明加入符号表
 * @param functionDecl
 */
func (selfx Enter) visitFunctionDecl(caller *IAstVisitor, functionDecl *FunctionDecl) interface{} {
	if selfx.symTable.hasSymbol(functionDecl.Name) {
		fmt.Println("Dumplicate symbol: " + functionDecl.Name)
	}
	selfx.symTable.enterSymbol(functionDecl.Name, functionDecl, SymKind_Function)
	return nil
}

/**
 * 把变量声明加入符号表
 * @param variableDecl
 */
func (selfx Enter) visitVariableDecl(caller *IAstVisitor, variableDecl *VariableDecl) interface{} {
	if selfx.symTable.hasSymbol(variableDecl.Name) {
		fmt.Println("Dumplicate symbol: " + variableDecl.Name)
	}
	selfx.symTable.enterSymbol(variableDecl.Name, variableDecl, SymKind_Variable)
	return nil
}

/////////////////////////////////////////////////////////////////////////
// 引用消解（Refrence Resolving）
// 1.函数引用消解
// 2.变量应用消解

/**
 * 引用消解
 * 遍历AST。如果发现函数调用和变量引用，就去找它的定义。
 */
type RefResolver struct {
	AstVisitor
	symTable SymTable
}

func NewRefResolver(symTable SymTable) *RefResolver {
	return &RefResolver{
		symTable: symTable,
	}
}

func (selfx RefResolver) Visit(caller *IAstVisitor, node *IAstNode) interface{} {
	return (*node).Accept(caller)
}

//消解函数引用
func (selfx RefResolver) visitFunctionCall(caller *IAstVisitor, functionCall *FunctionCall) interface{} {
	var symbol = selfx.symTable.getSymbol(functionCall.Name)
	// if symbol != nil {
	// 	fmt.Println("symbol.Value: ", reflect.TypeOf(symbol.Value))
	// }

	if symbol != nil && symbol.Kind == SymKind_Function {
		fd, ok := (symbol.Value).(*FunctionDecl)
		if ok {
			functionCall.FuncDecl = fd
		} else {
			fmt.Println("symbol.Decl to FunctionDecl error !!!")
		}
	} else {
		if !strings.HasPrefix(functionCall.Name, "nl.") {
			//除系统内置函数外，找不到引用，要报错
			fmt.Println("Error: cannot find declaration of function " + functionCall.Name)
		}
	}

	return nil
}

//消解变量引用
func (selfx RefResolver) visitVariable(caller *IAstVisitor, variable *Variable) interface{} {
	var symbol = selfx.symTable.getSymbol(variable.Name)
	if symbol != nil && symbol.Kind == SymKind_Variable {
		fd, ok := (symbol.Value).(VariableDecl)
		if ok {
			variable.VarDecl = &fd
		} else {
			fmt.Println("symbol.Decl to VariableDecl error !!!")
		}
	} else {
		fmt.Println("Error: cannot find declaration of variable " + variable.Name)
	}

	return nil
}
